﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;

namespace AF_Image
{
    public class AFImageHelper
    {
        public static void GenerateThumbnail(string orgImagePath, string newImagePath, int newWidth, int newHeight, EnumResizeMode resizeMode = EnumResizeMode.AutoAndRotation, List<WarterMark> WarterMark = null)
        {
            Image toSaveImage = GetThumbnailImage(orgImagePath, newWidth, newHeight, resizeMode);
            if (toSaveImage != null)
            {
                Graphics G = Graphics.FromImage(toSaveImage);
                G.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                G.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                G.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

                if (WarterMark != null)
                {
                    foreach (var item in WarterMark)
                    {
                        if (item != null)
                        {
                            using (Image waterMarkImage = Image.FromFile(item.FilePath))
                            {
                                switch (item.Align)
                                {
                                    case EnumAlign.TopLeft:
                                        G.DrawImage(waterMarkImage, item.Margin, item.Margin);
                                        break;
                                    case EnumAlign.TopCenter:
                                        G.DrawImage(waterMarkImage, (toSaveImage.Width - waterMarkImage.Width) / 2, item.Margin);
                                        break;
                                    case EnumAlign.TopRight:
                                        G.DrawImage(waterMarkImage, (toSaveImage.Width - waterMarkImage.Width - item.Margin), item.Margin);
                                        break;
                                    case EnumAlign.MiddleLeft:
                                        G.DrawImage(waterMarkImage, item.Margin, (toSaveImage.Height - waterMarkImage.Height) / 2);
                                        break;
                                    case EnumAlign.MiddleCenter:
                                        G.DrawImage(waterMarkImage, (toSaveImage.Width - waterMarkImage.Width) / 2, (toSaveImage.Height - waterMarkImage.Height) / 2);
                                        break;
                                    case EnumAlign.MiddleRight:
                                        G.DrawImage(waterMarkImage, (toSaveImage.Width - waterMarkImage.Width - item.Margin), (toSaveImage.Height - waterMarkImage.Height) / 2);
                                        break;
                                    case EnumAlign.BottomLeft:
                                        G.DrawImage(waterMarkImage, item.Margin, (toSaveImage.Height - waterMarkImage.Height - item.Margin));
                                        break;
                                    case EnumAlign.BottomMiddle:
                                        G.DrawImage(waterMarkImage, (toSaveImage.Width - waterMarkImage.Width) / 2, (toSaveImage.Height - waterMarkImage.Height - item.Margin));
                                        break;
                                    case EnumAlign.BottomRight:
                                        G.DrawImage(waterMarkImage, (toSaveImage.Width - waterMarkImage.Width - item.Margin), (toSaveImage.Height - waterMarkImage.Height - item.Margin));
                                        break;
                                    default:
                                        break;
                                }
                            }
                        }
                    }
                    G.Save();
                }
                System.Drawing.Imaging.ImageCodecInfo ici = GetEncoderInfo("image/jpeg");
                if (ici != null)
                {
                    System.Drawing.Imaging.EncoderParameters ep = new System.Drawing.Imaging.EncoderParameters(1);
                    ep.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)100);
                    toSaveImage.Save(newImagePath, ici, ep);

                    ep.Dispose();
                    ep = null;
                    ici = null;
                }

                if (toSaveImage != null)
                {
                    toSaveImage.Dispose();
                    toSaveImage = null;
                }
            }
        }

        private static Image GetThumbnailImage(string orgImagePath, int targetWidth, int targetHeight, EnumResizeMode resizeMode = EnumResizeMode.AutoAndRotation)
        {
            Image result = null;
            Image orgImage = Image.FromFile(orgImagePath);
            try
            {
                bool NeedRotation = orgImage.Width > orgImage.Height && resizeMode == EnumResizeMode.AutoAndRotation;
                int orgWidth = NeedRotation ? orgImage.Height : orgImage.Width;
                int orgHeight = NeedRotation ? orgImage.Width : orgImage.Height;
                if (NeedRotation)
                {
                    orgImage = RotateImg(orgImage, -90);
                }
                PicSize newSize = AdjustSize(targetWidth, targetHeight, orgWidth, orgHeight, resizeMode);
                result = orgImage.GetThumbnailImage(newSize.Width, newSize.Height, new Image.GetThumbnailImageAbort(() => { return false; }), IntPtr.Zero);
            }
            finally
            {
                orgImage.Dispose();
                orgImage = null;
            }
            return result;
        }



        public static PicSize AdjustSize(int spcWidth, int spcHeight, int orgWidth, int orgHeight, EnumResizeMode resizeMode = EnumResizeMode.AutoAndRotation)
        {
            PicSize result = new PicSize();
            // 原始宽高在指定宽高范围内，不作任何处理
            if (orgWidth <= spcWidth && orgHeight <= spcHeight)
            {
                result.Width = orgWidth;
                result.Height = orgHeight;
            }
            else
            {
                //计算宽高比系数
                float w = orgWidth / (float)spcWidth;
                float h = orgHeight / (float)spcHeight;
                result.Width = spcWidth;
                result.Height = spcHeight;

                switch (resizeMode)
                {
                    case EnumResizeMode.FixedWidth:
                        result.Width = spcWidth;
                        result.Height = (int)(w >= 1 ? Math.Round(orgHeight / w) : Math.Round(orgHeight * w));
                        break;
                    case EnumResizeMode.FixedHeight:
                        result.Height = spcHeight;
                        result.Width = (int)(h >= 1 ? Math.Round(orgWidth / h) : Math.Round(orgWidth * h));
                        break;
                    case EnumResizeMode.FixedWidthAndHeight:
                        result.Height = spcHeight;
                        result.Width = spcWidth;
                        break;
                    default:
                        // 宽度比大于高度比,按宽缩放
                        if (w > h)
                        {
                            result.Width = spcWidth;
                            result.Height = (int)(w >= 1 ? Math.Round(orgHeight / w) : Math.Round(orgHeight * w));
                        }
                        // 宽度比小于高度比,按高缩放
                        else if (w < h)
                        {
                            result.Height = spcHeight;
                            result.Width = (int)(h >= 1 ? Math.Round(orgWidth / h) : Math.Round(orgWidth * h));
                        }
                        break;
                }

            }
            return result;
        }

        private static ImageCodecInfo GetEncoderInfo(String mimeType)
        {
            int j;
            ImageCodecInfo[] encoders;
            encoders = ImageCodecInfo.GetImageEncoders();
            for (j = 0; j < encoders.Length; ++j)
            {
                if (encoders[j].MimeType == mimeType)
                    return encoders[j];
            }
            return null;
        }

        public static Image RotateImg(Image source, int angle)
        {

            angle = angle % 360;


            //弧度转换  

            double radian = angle * Math.PI / 180.0;

            double cos = Math.Cos(radian);

            double sin = Math.Sin(radian);


            //原图的宽和高  

            int w = source.Width;

            int h = source.Height;

            int W = (int)(Math.Max(Math.Abs(w * cos - h * sin), Math.Abs(w * cos + h * sin)));

            int H = (int)(Math.Max(Math.Abs(w * sin - h * cos), Math.Abs(w * sin + h * cos)));


            //目标位图  

            Bitmap dsImage = new Bitmap(W, H);

            System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(dsImage);

            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;


            //计算偏移量  

            Point Offset = new Point((W - w) / 2, (H - h) / 2);


            //构造图像显示区域：让图像的中心与窗口的中心点一致  

            Rectangle rect = new Rectangle(Offset.X, Offset.Y, w, h);

            Point center = new Point(rect.X + rect.Width / 2, rect.Y + rect.Height / 2);


            g.TranslateTransform(center.X, center.Y);

            g.RotateTransform(360 - angle);


            //恢复图像在水平和垂直方向的平移  

            g.TranslateTransform(-center.X, -center.Y);

            g.DrawImage(source, rect);


            //重至绘图的所有变换  

            g.ResetTransform();


            g.Save();

            g.Dispose();

            //保存旋转后的图片  

            source.Dispose();
            return dsImage;
        }


        public static Image RotateImg(string filename, int angle)
        {
            return RotateImg(GetSourceImg(filename), angle);
        }

        public static Image GetSourceImg(string filename)
        {
            Image img;
            img = Bitmap.FromFile(filename);
            return img;
        }

        public struct PicSize
        {
            public int Width;
            public int Height;
        }
    }
}
